#include "StdAfx.h"
#include "Rect.h"

namespace gfx {

Rect::Rect(void)
{
}

Rect::Rect(const Rect& rect)
{
	*this = rect;
}

Rect::Rect(int width, int height) : size_(width, height)
{

}

Rect::Rect(int x, int y, int width, int height) : origin_(x, y)
													, size_(width, height)
{

}

Rect::Rect(const Point& origin, const gfx::Size& size) : origin_(origin)
													, size_(size)
{

}

Rect::Rect(const gfx::Size& size) : size_(size)
{

}

Rect::~Rect(void)
{
}

void Rect::Offset(int horizontal, int vertical)
{
	origin_.Offset(horizontal, vertical);
}

void Rect::Offset(const gfx::Point& point)
{
	Offset(point.X(), point.Y());
}

void Rect::Inset(int left, int top, int right, int bottom)
{
	Offset(left, top);
	SetWidth(Width() - left - right > 0 ? Width() - left - right : 0);
	SetHeight(Height() - top - bottom > 0 ? Height() - top - bottom : 0);
}

void Rect::Inset(int horizontal, int vertical)
{
	Inset(horizontal, vertical, horizontal, vertical);
}

void Rect::Inset(const gfx::Insets& insets)
{
	Inset(insets.Left(), insets.Top(), insets.Right(), insets.Bottom());
}

bool Rect::operator == (const Rect& rhs) const
{
	return this->origin_ == rhs.origin_ && this->size_ == rhs.size_;
}

bool Rect::operator!=(const Rect& rhs) const
{
	return !(*this == rhs);
}

Rect& Rect::operator=(const Rect& rhs)
{
	this->origin_ = rhs.origin_;
	this->size_ = rhs.size_;

	return *this;
}

bool Rect::Contains(int point_x, int point_y) const
{
	return (point_x >= X() && point_x < Right()) &&
		   (point_y >= Y() && point_y < Bottom());
}

bool Rect::Contains(const gfx::Rect& rect)const
{
	return rect.X() >= X() && rect.Right() <= Right() &&
		   rect.Y() >= Y() && rect.Bottom() <= Bottom();
}

bool Rect::Intersects(const gfx::Rect& rect) const
{
	return !(rect.X() >= Right() || rect.Right() <= X() ||
		rect.Y() >= Bottom() || rect.Bottom() <= Y());
}

Rect Rect::Intersect(const Rect& rect) const
{
	int x = X() > rect.X() ? X() : rect.X();
	int y = Y() > rect.Y() ? Y() : rect.Y();
	int right = Right() < rect.Right() ? Right() : rect.Right();
	int bottom = Bottom() < rect.Bottom() ? Bottom() : rect.Bottom();

	if(x >= right || y >= bottom)
	{
		x = y = right = bottom = 0;
	}

	return Rect(x, y, right - x, bottom - y);
}

Rect Rect::Union(const Rect& rect) const
{
	if(IsEmpty())
	{
		return rect;
	}
	
	if(rect.IsEmpty())
	{
		return *this;
	}

	int x = X() < rect.X() ? X() : rect.X();
	int y = Y() < rect.Y() ? Y() : rect.Y();
	int right = Right() > rect.Right() ? Right() : rect.Right();
	int bottom = Bottom() > rect.Bottom() ? Bottom() : rect.Bottom();

	return Rect(x, y, right - x, bottom - y);
}

Rect Rect::Subtract(const Rect& rect) const
{
	// boundary cases:
	if (!Intersects(rect))
		return *this;
	if (rect.Contains(*this))
		return Rect();

	int rx = X();
	int ry = Y();
	int rr = Right();
	int rb = Bottom();

	if (rect.Y() <= Y() && rect.Bottom() >= Bottom()) {
		// complete intersection in the y-direction
		if (rect.X() <= X()) {
			rx = rect.Right();
		} else {
			rr = rect.X();
		}
	} else if (rect.X() <= X() && rect.Right() >= Right()) {
		// complete intersection in the x-direction
		if (rect.Y() <= Y()) {
			ry = rect.Bottom();
		} else {
			rb = rect.Y();
		}
	}
	return Rect(rx, ry, rr - rx, rb - ry);
}

Point Rect::CenterPoint() const
{
	return Point((X() + Width() - 1) / 2, (Y() + Height() - 1) / 2);
}

} // namespace gfx